/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.txweb.validator;

import com.jspx.io.AutoReadTextFile;
import com.jspx.txweb.annotation.Safety;
import com.jspx.txweb.util.RequestUtil;
import com.jspx.utils.*;
import com.jspx.txweb.validator.tag.ValidatorElement;
import com.jspx.txweb.validator.tag.ValidElement;
import com.jspx.boot.environment.EnvironmentTemplate;
import com.jspx.boot.environment.Environment;
import com.jspx.boot.environment.Placeholder;
import com.jspx.boot.EnvFactory;
import com.jspx.json.JSONStringer;
import com.jspx.scriptmark.XmlEngine;
import com.jspx.scriptmark.ScriptRunner;
import com.jspx.scriptmark.core.TagNode;
import com.jspx.scriptmark.core.script.TemplateScriptEngine;
import com.jspx.scriptmark.parse.XmlEngineImpl;
import com.jspx.upload.MultipartRequest;
import com.jspx.txweb.support.ActionSupport;

import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
import java.util.List;
import java.util.HashMap;
import java.io.IOException;
import java.io.Serializable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by IntelliJ IDEA.
 * User:chenYuan (mail:39793751@qq.com)
 * Date: 2007-4-16
 * Time: 0:01:15
 * com.jspx.validator.DataTypeValidator
 */
@SuppressWarnings({"ALL"})
public class DataTypeValidator implements Validator, Serializable {
    private static final Logger log = LoggerFactory.getLogger(DataTypeValidator.class);

    private String configFile = "validator.xml";
    private Object checkObject = null;
    public static final String note = "note";
    public static final String error = "error";
    public static final String all = "all";
    public static final String Tag_VALIDATOR = "validator";
    public static final String Tag_VALIDATION = "validation";
    protected static final String errorValidation = "ErrorConfig";
    private String encode = Environment.defaultEncode;
    private String formId = StringUtil.empty;
    private EnvironmentTemplate environmentTemplate = EnvFactory.getEnvironmentTemplate();
    private boolean debug = environmentTemplate.getBoolean(Environment.logJspxDebug);

    public String getEncode() {
        return encode;
    }

    public void setEncode(String encode) {
        this.encode = encode;
    }

    public String getFormId() {
        return formId;
    }


    public void setFormId(String formId) {
        if (formId!=null) this.formId = formId.toLowerCase();
    }

    public String getConfigFile() {
        return configFile;
    }


    public void setConfigFile(String configFile) {
        this.configFile = configFile;
    }

    public Object getCheckObject() {
        return checkObject;
    }

    public void setCheckObject(Object checkObject) {
        this.checkObject = checkObject;
    }

    private String getFileName() {
        String fileNamePath = configFile;
        if (FileUtil.isFileExist(fileNamePath)) return fileNamePath;
        fileNamePath = environmentTemplate.getString(Environment.defaultPath) + fileNamePath;
        if (FileUtil.isFileExist(fileNamePath)) return fileNamePath;
        URL url = ClassUtil.getResource(configFile);
        if (url == null) {
            url = ClassUtil.getResource("/" + configFile);
            if (url != null) {
                fileNamePath = url.getPath();
            }
        }
        return fileNamePath;
    }

    private  String geteValidatorKey()
    {
        StringBuffer sb = new StringBuffer();
        sb.append(configFile).append(".").append(formId);
        return sb.toString();
    }

    private List<TagNode> getConfig() throws Exception {
        if (!StringUtil.hasLength(formId)) return new ArrayList<TagNode>();

        String fileNamePath = getFileName();
        //载入配置 begin
        AutoReadTextFile readTextFile = new AutoReadTextFile();
        readTextFile.setEncode(encode);
        readTextFile.setFile(fileNamePath);
        String xml = StringUtil.empty;
        try {
            xml =readTextFile.getContent();
        } catch (Exception e) {
            log.info(fileNamePath +"　not find DataTypeValidator XML file " + fileNamePath + "  数据验证的XML文件没有找到",e);
            return new ArrayList<TagNode>();
        }
        XmlEngine xmlEngine = new XmlEngineImpl();
        xmlEngine.putTag(Tag_VALIDATOR, ValidatorElement.class.getName());
        List<TagNode> nodes = xmlEngine.getTagNodes(xml);
        for (TagNode node : nodes) {
            ValidatorElement validatorElement = (ValidatorElement) node;
            if (validatorElement.getFormId().equalsIgnoreCase(formId))
                return validatorElement.getValidElements();
        }
        nodes.clear();
        return new ArrayList<TagNode>();
    }


    public String getXML() throws Exception {
        StringBuilder sb = new StringBuilder("<validator formId=\"" + formId + "\">\r\n");
        List<TagNode> tagNodes = getConfig();
        if (tagNodes == null) {
            throw new IOException("DataTypeValidator not find configFile XML file " + configFile + " formId:" + formId + " 数据验证的XML文件没有找到相应的配置");
        }
        for (TagNode tagNode : tagNodes) {
            ValidElement validElement = (ValidElement) tagNode;
            if (StringUtil.isNULL(validElement.getUrl())) {
                sb.append("<" + Tag_VALIDATOR + " dataType=\"").append(validElement.getDataType()).append("\" field=\"").append(validElement.getField()).append("\" noteId=\"").append(validElement.getNoteId()).append("\" needed=\"").append(validElement.isNeeded()).append("\">\r\n");
            } else
                sb.append("<" + Tag_VALIDATOR + " dataType=\"").append(validElement.getDataType()).append("\" url=\"").append(validElement.getUrl()).append("\" field=\"").append(validElement.getField()).append("\" noteId=\"").append(validElement.getNoteId()).append("\" needed=\"").append(validElement.isNeeded()).append("\">\r\n");

            sb.append("     <note>").append(validElement.getNote()).append("</note>\r\n");
            sb.append("     <error>").append(validElement.getError()).append("</error>\r\n");
            sb.append("</" + Tag_VALIDATOR + ">\r\n");
        }
        sb.append("</validator>\r\n");

        EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
        Placeholder placeholder = EnvFactory.getPlaceholder();
        return placeholder.processTemplate(envTemplate.getVariableMap(), sb.toString());
    }

    public String getJson() throws Exception {
        List<TagNode> tagNodes = getConfig();
        if (tagNodes == null||tagNodes.isEmpty()) {
            log.debug("DataTypeValidator not find configFile XML file " + configFile + " formId:" + formId + " 数据验证的XML文件没有找到相应的配置");
            return StringUtil.empty;
        }
        JSONStringer ja = new JSONStringer();
        ja.array();
        for (TagNode tagNode : tagNodes) {
            ValidElement validElement = (ValidElement) tagNode;
            ja.object();
            ja.key("field").value(validElement.getField());
            ja.key("noteId").value(validElement.getNoteId());
            ja.key("dataType").value(XMLUtil.escapeDecrypt(validElement.getDataType()));
            ja.key("url").value(validElement.getUrl());
            ja.key("needed").value(validElement.isNeeded());
            ja.key("note").value(XMLUtil.escapeDecrypt(validElement.getNote()));
            ja.key("error").value(validElement.getError());
            ja.endObject();
        }
        ja.endArray();
        EnvironmentTemplate envTemplate = EnvFactory.getEnvironmentTemplate();
        Placeholder placeholder = EnvFactory.getPlaceholder();
        return placeholder.processTemplate(envTemplate.getVariableMap(), ja.toString());
    }

    /**
     * 在这里验证
     *
     * @param valueMap 验证的数据
     * @param infoType 要返回的结果类型
     * @return 保持在map中返回
     * @throws Exception 其他错误
     *                   解析错误
     */
    private Map<String, String> getInformationForMap(Map<String, Object> valueMap, String infoType) throws Exception {
        Map<String, String> result = new HashMap<String, String>();
        Placeholder placeholder = EnvFactory.getPlaceholder();
        ScriptRunner scriptRunner = new TemplateScriptEngine();
        if (valueMap != null)
            for (String name : valueMap.keySet())
                scriptRunner.put(name, valueMap.get(name));

        List<TagNode> tagNodes = getConfig();
        if (tagNodes == null) {
            throw new NullPointerException("Not Find Validator file:" + configFile + "  formId:" + formId);
        }
        try {
            for (TagNode tagNode : tagNodes) {
                ValidElement validElement = (ValidElement) tagNode;
                Object ov = valueMap.get(validElement.getField());
                boolean isNeed = validElement.isNeeded();
                if (!isNeed && (ov != null) && (ov instanceof String) && !StringUtil.isNULL((String) ov)) isNeed = true;
                if (!isNeed) continue;
                String expression = placeholder.processTemplate(valueMap, validElement.getDataType());
                if (expression.startsWith(" ")) expression = expression.trim();

                //checkbox 判断
                String field = validElement.getField();
                if (field.indexOf(StringUtil.SEMICOLON) != -1) {
                    field = StringUtil.quote(field, false) + ".toArray(';')";
                }
                expression = field + "." + expression;
                if (expression.contains("$(")) {
                    //web界面的验证，跳过
                    continue;

                }
                if (!expression.trim().endsWith(")") && !StringUtil.indexOfArray(expression, new String[]{">", "<", "=", "+", "-", "*", "/"}))
                    expression = expression.trim() + "()";

                boolean b = ObjectUtil.toBoolean(scriptRunner.eval(expression,0));
                if (!b && error.equalsIgnoreCase(infoType)) {
                    result.put(validElement.getField(), validElement.getError());
                } else if (note.equalsIgnoreCase(infoType)) {
                    result.put(validElement.getField(), validElement.getNote());
                }
            }
        } finally {
            scriptRunner.exit();
        }
        return result;
    }


    /**
     * 完成类型转换
     *
     * @param infoType 需要返回的信息类型
     * @return 返回验证结果
     * @throws Exception 其他错误
     *                   解析错误
     */
    @SuppressWarnings("unchecked")
    public Map<String, String> getInformation(String infoType) throws Exception {
        if (checkObject instanceof ActionSupport) {
            ActionSupport actionSupport = (ActionSupport) checkObject;
            return getInformationForMap(RequestUtil.getRequestMap(actionSupport.getRequest()), infoType);
        } else if (checkObject instanceof MultipartRequest || checkObject instanceof HttpServletRequest) {
            return getInformationForMap(RequestUtil.getRequestMap(((HttpServletRequest) checkObject)), infoType);
        } else if (checkObject instanceof Map) {
            return getInformationForMap((Map) checkObject, infoType);
        } else {
            return getInformationForMap(BeanUtil.getMap(checkObject), infoType);
        }
    }

}